home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1995 #5 & #6 / Amiga Plus CD - 1995 - No. 5 and 6.iso / pd / netz / term / extras / source / term-source.lha / termFileBuffer.c < prev    next >
C/C++ Source or Header  |  1995-06-17  |  22KB  |  1,113 lines

  1. /*
  2. **    termFileBuffer.c
  3. **
  4. **    Double-buffered file I/O routines
  5. **
  6. **    Copyright © 1990-1995 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. */
  9.  
  10. #include "termGlobal.h"
  11.  
  12.     /* Argument types. */
  13.  
  14. enum    {    ARG_NAME,ARG_MODE };
  15. enum    {    ARG_OFFSET,ARG_ORIGIN };
  16.  
  17.     /* Seek offsets. */
  18.  
  19. enum    {    SEEKFILE_SET,SEEKFILE_CURR,SEEKFILE_END };
  20.  
  21.     /* Command codes. */
  22.  
  23. enum    {    BUF_CLOSE,BUF_SEEK,BUF_FILL,BUF_FLUSH };
  24.  
  25.     /* ObtainInfo(struct Buffer *File):
  26.      *
  27.      *    Obtain information on the disk a buffered file
  28.      *    resides on.
  29.      */
  30.  
  31. STATIC VOID __regargs
  32. ObtainInfo(struct Buffer *File)
  33. {
  34.         /* Lock on the path available? */
  35.  
  36.     if(File -> InfoPort)
  37.     {
  38.             /* This is more or less a trick; we try to obtain
  39.              * information on a filing system without having a
  40.              * shared lock on it. We cannot DupLockFromFH()
  41.              * the file handle since it was allocated for
  42.              * exclusive access. The ACTION_DISK_INFO packet
  43.              * solves this problem as it requires only the
  44.              * filing system task (MsgPort) to be given.
  45.              */
  46.  
  47.         if(!DoPkt1(File -> InfoPort,ACTION_DISK_INFO,MKBADDR(&File -> InfoData)))
  48.         {
  49.             File -> InfoData . id_NumBlocks        = 0;
  50.             File -> InfoData . id_BytesPerBlock    = 0;
  51.         }
  52.     }
  53. }
  54.  
  55.     /* FileBufferServer():
  56.      *
  57.      *    Background process to handle the buffering
  58.      *    of a filehandle, automatically gets invoked
  59.      *    when a file is opened.
  60.      */
  61.  
  62. STATIC VOID __saveds
  63. FileBufferServer(VOID)
  64. {
  65.     struct MsgPort    *Port;
  66.     struct Buffer    *Buffer;
  67.     BYTE         Terminated = FALSE,
  68.              Done,
  69.              WasFull;
  70.     UBYTE        *String;
  71.     APTR         Data;
  72.     LONG         Length;
  73.     BPTR         SomeLock;
  74.  
  75.         /* Wait for startup message (-> Buffer). */
  76.  
  77.     Port = &((struct Process *)SysBase -> ThisTask) -> pr_MsgPort;
  78.  
  79.     WaitPort(Port);
  80.  
  81.     Buffer = (struct Buffer *)GetMsg(Port);
  82.  
  83.         /* Open the file and obtain a filehandle. */
  84.  
  85.     String = (STRPTR)Buffer -> ActionData[ARG_MODE];
  86.  
  87.     Buffer -> WriteAccess = TRUE;
  88.  
  89.         /* Put the message into the list. */
  90.  
  91.     ObtainSemaphore(&DoubleBufferSemaphore);
  92.  
  93.     AddTail(&DoubleBufferList,(struct Node *)Buffer);
  94.  
  95.     ReleaseSemaphore(&DoubleBufferSemaphore);
  96.  
  97.         /* Remember the opening date. */
  98.  
  99.     DateStamp(&Buffer -> OpenDate);
  100.  
  101.         /* Check for the open type. */
  102.  
  103.     switch(String[0])
  104.     {
  105.         case 'r':
  106.  
  107.             if(String[1] == '+')
  108.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_READWRITE);
  109.             else
  110.             {
  111.                 Buffer -> WriteAccess = FALSE;
  112.  
  113.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_OLDFILE);
  114.             }
  115.  
  116.             break;
  117.  
  118.         case 'w':
  119.  
  120.             if(String[1] == '+')
  121.             {
  122.                 if(SomeLock = Lock((STRPTR)Buffer -> ActionData[ARG_NAME],ACCESS_WRITE))
  123.                 {
  124.                     UnLock(SomeLock);
  125.  
  126.                     DeleteFile((STRPTR)Buffer -> ActionData[ARG_NAME]);
  127.                 }
  128.  
  129.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_READWRITE);
  130.             }
  131.             else
  132.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_NEWFILE);
  133.  
  134.             break;
  135.  
  136.         case 'a':
  137.  
  138.             if(SomeLock = Lock((STRPTR)Buffer -> ActionData[ARG_NAME],ACCESS_WRITE))
  139.             {
  140.                 UnLock(SomeLock);
  141.  
  142.                 if(Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_READWRITE))
  143.                 {
  144.                     if(Seek(Buffer -> FileHandle,0,OFFSET_END) == -1)
  145.                     {
  146.                         Close(Buffer -> FileHandle);
  147.  
  148.                         Buffer -> FileHandle = NULL;
  149.                     }
  150.                 }
  151.             }
  152.             else
  153.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_NEWFILE);
  154.  
  155.             break;
  156.     }
  157.  
  158.         /* Clear signal bit. */
  159.  
  160.     ClrSignal(SIG_COMMAND);
  161.  
  162.         /* Did the file open? */
  163.  
  164.     if(Buffer -> FileHandle)
  165.     {
  166.         Buffer -> Data        = Buffer -> DataBuffer[0];
  167.         Buffer -> DataCount    = 1;
  168.         Buffer -> Fresh        = TRUE;
  169.  
  170.             /* If not in write mode fill the buffers. */
  171.  
  172.         if(!Buffer -> WriteAccess)
  173.         {
  174.                 /* Fill the first one synchronously. */
  175.  
  176.             Buffer -> ReadBufFull    = Read(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufLength);
  177.             Buffer -> Read        = TRUE;
  178.             Buffer -> RealPosition    = Buffer -> ReadBufFull;
  179.  
  180.                 /* Restart caller. */
  181.  
  182.             Signal(Buffer -> Caller,SIG_HANDSHAKE);
  183.  
  184.                 /* Fill the second buffe asynchronously. */
  185.  
  186.             Buffer -> DataLength[1]    = Buffer -> Cached = Read(Buffer -> FileHandle,Buffer -> DataBuffer[1],Buffer -> BufLength);
  187.             Buffer -> RealPosition += Buffer -> Cached;
  188.         }
  189.         else
  190.         {
  191.             Buffer -> InfoPort = ((struct FileHandle *)BADDR(Buffer -> FileHandle)) -> fh_Type;
  192.  
  193.             ObtainInfo(Buffer);
  194.  
  195.             Signal(Buffer -> Caller,SIG_HANDSHAKE);
  196.         }
  197.     }
  198.     else
  199.         Terminated = TRUE;
  200.  
  201.         /* Go into loop waiting for commands. */
  202.  
  203.     while(!Terminated)
  204.     {
  205.         Wait(SIG_COMMAND);
  206.  
  207.         Done = FALSE;
  208.  
  209.         Buffer -> Result = 0;
  210.  
  211.             /* Take care of each action. */
  212.  
  213.         switch(Buffer -> Action)
  214.         {
  215.                 /* Close the file, flush any dirty
  216.                  * buffers and exit.
  217.                  */
  218.  
  219.             case BUF_CLOSE:
  220.  
  221.                 Buffer -> Result = TRUE;
  222.  
  223.                 if(Buffer -> BufPosition && Buffer -> Written)
  224.                 {
  225.                     if(Write(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufPosition) != Buffer -> BufPosition)
  226.                         Buffer -> Result = FALSE;
  227.                 }
  228.  
  229.                 if(!Close(Buffer -> FileHandle))
  230.                     Buffer -> Result = FALSE;
  231.  
  232.                 Terminated = TRUE;
  233.  
  234.                 break;
  235.  
  236.                 /* Seek to a specific file position. */
  237.  
  238.             case BUF_SEEK:
  239.  
  240.                 Buffer -> Result = 0;
  241.  
  242.                     /* Do nothing if buffer is still
  243.                      * untouched and we are required
  244.                      * to seek back to the beginning
  245.                      * of the file.
  246.                      */
  247.  
  248.                 if(Buffer -> Fresh && !Buffer -> ActionData[ARG_OFFSET] && Buffer -> ActionData[ARG_ORIGIN] == SEEKFILE_SET)
  249.                 {
  250.                     Signal(Buffer -> Caller,SIG_HANDSHAKE);
  251.  
  252.                     Done = TRUE;
  253.                 }
  254.                 else
  255.                 {
  256.                     Buffer -> WriteBufFull    = Buffer -> BufLength;
  257.                     Buffer -> Read        = FALSE;
  258.  
  259.                     if(Buffer -> BufPosition && Buffer -> Written)
  260.                     {
  261.                         if(Write(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufPosition) != Buffer -> BufPosition)
  262.                             Buffer -> Result = -1;
  263.                         else
  264.                             ObtainInfo(Buffer);
  265.                     }
  266.  
  267.                     if(!Buffer -> Result)
  268.                     {
  269.                         Buffer -> Result = Buffer -> RealPosition - (Buffer -> ReadBufFull + Buffer -> Cached);
  270.  
  271.                         switch(Buffer -> ActionData[ARG_ORIGIN])
  272.                         {
  273.                             case SEEKFILE_SET:
  274.  
  275.                                 if(Seek(Buffer -> FileHandle,Buffer -> ActionData[ARG_OFFSET],OFFSET_BEGINNING) != -1)
  276.                                     Buffer -> RealPosition = Buffer -> ActionData[ARG_OFFSET];
  277.                                 else
  278.                                     Buffer -> Result = -1;
  279.  
  280.                                 break;
  281.  
  282.                             case SEEKFILE_CURR:
  283.  
  284.                                 if(!Buffer -> WriteAccess && Buffer -> ActionData[ARG_OFFSET] >= 0 && Buffer -> ReadBufFull - Buffer -> ActionData[ARG_OFFSET] >= 0)
  285.                                 {
  286.                                     Buffer -> ReadBufFull    -= Buffer -> ActionData[ARG_OFFSET];
  287.                                     Buffer -> Data        += Buffer -> ActionData[ARG_OFFSET];
  288.  
  289.                                     Signal(Buffer -> Caller,SIG_HANDSHAKE);
  290.  
  291.                                     Done = TRUE;
  292.  
  293.                                     break;
  294.                                 }
  295.  
  296.                                 if(Seek(Buffer -> FileHandle,-(Buffer -> ReadBufFull + Buffer -> Cached) + Buffer -> ActionData[ARG_OFFSET],OFFSET_CURRENT) != -1)
  297.                                     Buffer -> RealPosition += -(Buffer -> ReadBufFull + Buffer -> Cached) + Buffer -> ActionData[ARG_OFFSET];
  298.                                 else
  299.                                     Buffer -> Result = -1;
  300.  
  301.                                 break;
  302.  
  303.                             case SEEKFILE_END:
  304.  
  305.                                 if(Seek(Buffer -> FileHandle,Buffer -> ActionData[ARG_OFFSET],OFFSET_END) != -1)
  306.                                     Buffer -> RealPosition = Seek(Buffer -> FileHandle,0,OFFSET_CURRENT);
  307.                                 else
  308.                                     Buffer -> Result = -1;
  309.  
  310.                                 break;
  311.  
  312.                             default:
  313.  
  314.                                 Buffer -> Result = -1;
  315.                         }
  316.  
  317.                         Buffer -> ReadBufFull = 0;
  318.  
  319.                         if(Buffer -> Result != -1)
  320.                         {
  321.                             Buffer -> Data        = Buffer -> DataBuffer[0];
  322.                             Buffer -> DataCount    = 1;
  323.  
  324.                             if(!Buffer -> WriteAccess)
  325.                             {
  326.                                 Buffer -> ReadBufFull     = Read(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufLength);
  327.                                 Buffer -> WriteBufFull     = 0;
  328.                                 Buffer -> Read         = TRUE;
  329.                                 Buffer -> RealPosition    += Buffer -> ReadBufFull;
  330.  
  331.                                 if(Buffer -> ReadBufFull)
  332.                                 {
  333.                                     Buffer -> Cached = Buffer -> DataLength[1] = Read(Buffer -> FileHandle,Buffer -> DataBuffer[1],Buffer -> BufLength);
  334.  
  335.                                     Buffer -> RealPosition += Buffer -> Cached;
  336.                                 }
  337.                             }
  338.                         }
  339.                         else
  340.                             Buffer -> LastActionFailed = TRUE;
  341.                     }
  342.                     else
  343.                         Buffer -> ReadBufFull = 0;
  344.  
  345.                     Buffer -> BufPosition    = 0;
  346.                     Buffer -> Written    = FALSE;
  347.                 }
  348.  
  349.                 break;
  350.  
  351.                 /* Fill the buffer with fresh data. */
  352.  
  353.             case BUF_FILL:
  354.  
  355.                 Buffer -> Data        = Buffer -> DataBuffer[Buffer -> DataCount];
  356.                 Buffer -> ReadBufFull    = Buffer -> DataLength[Buffer -> DataCount];
  357.                 Buffer -> WriteBufFull    = 0;
  358.                 Buffer -> BufPosition    = 0;
  359.                 Buffer -> Read        = TRUE;
  360.                 Buffer -> Written    = FALSE;
  361.                 Buffer -> Fresh        = FALSE;
  362.  
  363.                 if(Buffer -> ReadBufFull)
  364.                     WasFull = TRUE;
  365.                 else
  366.                     WasFull = FALSE;
  367.  
  368.                     /* The buffer contents have been
  369.                      * swapped, now wake the caller
  370.                      * up and fill the next buffer
  371.                      * asynchronously.
  372.                      */
  373.  
  374.                 Signal(Buffer -> Caller,SIG_HANDSHAKE);
  375.  
  376.                 Done = TRUE;
  377.  
  378.                 if(WasFull)
  379.                 {
  380.                     Buffer -> DataCount = (Buffer -> DataCount + 1) % BUFFER_NUMBER;
  381.  
  382.                     Buffer -> Cached = Buffer -> DataLength[Buffer -> DataCount] = Read(Buffer -> FileHandle,Buffer -> DataBuffer[Buffer -> DataCount],Buffer -> BufLength);
  383.  
  384.                     Buffer -> RealPosition += Buffer -> Cached;
  385.  
  386.                     if(!Buffer -> DataLength[Buffer -> DataCount])
  387.                     {
  388.                         if(IoErr())
  389.                             Buffer -> LastActionFailed = TRUE;
  390.                     }
  391.                 }
  392.  
  393.                 break;
  394.  
  395.                 /* Flush the contents of the buffer to disk. */
  396.  
  397.             case BUF_FLUSH:
  398.  
  399.                 if(Buffer -> BufPosition && Buffer -> Written)
  400.                 {
  401.                     Data            = Buffer -> Data;
  402.                     Length            = Buffer -> BufPosition;
  403.  
  404.                     Buffer -> Data        = Buffer -> DataBuffer[Buffer -> DataCount];
  405.                     Buffer -> DataCount    = (Buffer -> DataCount + 1) % BUFFER_NUMBER;
  406.  
  407.                     Buffer -> ReadBufFull    = 0;
  408.                     Buffer -> WriteBufFull    = Buffer -> BufLength;
  409.                     Buffer -> BufPosition    = 0;
  410.                     Buffer -> Read        = FALSE;
  411.                     Buffer -> Written    = FALSE;
  412.  
  413.                     Signal(Buffer -> Caller,SIG_HANDSHAKE);
  414.  
  415.                     Done = TRUE;
  416.  
  417.                     if(Write(Buffer -> FileHandle,Data,Length) != Length)
  418.                         Buffer -> LastActionFailed = TRUE;
  419.                     else
  420.                     {
  421.                         ObtainInfo(Buffer);
  422.  
  423.                         Buffer -> RealPosition += Length;
  424.                     }
  425.                 }
  426.                 else
  427.                 {
  428.                     Buffer -> ReadBufFull    = 0;
  429.                     Buffer -> WriteBufFull    = Buffer -> BufLength;
  430.                     Buffer -> BufPosition    = 0;
  431.                     Buffer -> Read        = FALSE;
  432.                     Buffer -> Written    = FALSE;
  433.                 }
  434.  
  435.                 Buffer -> Fresh = FALSE;
  436.  
  437.                 break;
  438.         }
  439.  
  440.             /* Ring back if necessary. */
  441.  
  442.         if(!Done && !Terminated)
  443.             Signal(Buffer -> Caller,SIG_HANDSHAKE);
  444.     }
  445.  
  446.         /* Remove the message from the list. */
  447.  
  448.     ObtainSemaphore(&DoubleBufferSemaphore);
  449.  
  450.     Remove((struct Node *)Buffer);
  451.  
  452.     ReleaseSemaphore(&DoubleBufferSemaphore);
  453.  
  454.         /* Lock & quit. */
  455.  
  456.     Forbid();
  457.  
  458.     Signal(Buffer -> Caller,SIG_HANDSHAKE);
  459. }
  460.  
  461.     /* BufferFill(struct Buffer *Buffer):
  462.      *
  463.      *    Fills a given buffer with fresh data.
  464.      */
  465.  
  466. STATIC BYTE __inline
  467. BufferFill(struct Buffer *Buffer)
  468. {
  469.     if(Buffer -> LastActionFailed)
  470.         return(FALSE);
  471.     else
  472.     {
  473.         if(!Buffer -> ReadBufFull)
  474.         {
  475.             Buffer -> Action = BUF_FILL;
  476.  
  477.             Forbid();
  478.  
  479.             Signal(Buffer -> Child,SIG_COMMAND);
  480.  
  481.             ClrSignal(SIG_HANDSHAKE);
  482.  
  483.             Wait(SIG_HANDSHAKE);
  484.  
  485.             Permit();
  486.         }
  487.  
  488.         return(TRUE);
  489.     }
  490. }
  491.  
  492.     /* IsValidBuffer(struct Buffer *Buffer):
  493.      *
  494.      *    Scans the double buffered file list for
  495.      *    a valid entry.
  496.      */
  497.  
  498. STATIC BYTE __inline
  499. IsValidBuffer(struct Buffer *Buffer)
  500. {
  501.     BYTE         GotIt = FALSE;
  502.     struct Node    *Node;
  503.  
  504.     ObtainSemaphore(&DoubleBufferSemaphore);
  505.  
  506.     Node = DoubleBufferList . lh_Head;
  507.  
  508.     while(Node -> ln_Succ)
  509.     {
  510.         if(Buffer == (struct Buffer *)Node)
  511.         {
  512.             GotIt = TRUE;
  513.  
  514.             break;
  515.         }
  516.  
  517.         Node = Node -> ln_Succ;
  518.     }
  519.  
  520.     ReleaseSemaphore(&DoubleBufferSemaphore);
  521.  
  522.     return(GotIt);
  523. }
  524.  
  525.     /* OpenFileSimple(STRPTR Name,STRPTR AccessMode):
  526.      *
  527.      *    Open simple (unbuffered) file.
  528.      */
  529.  
  530. STATIC struct Buffer * __regargs
  531. OpenFileSimple(STRPTR Name,STRPTR AccessMode)
  532. {
  533.     struct Buffer *Buffer;
  534.  
  535.         /* Allocate buffer handle (dummy). */
  536.  
  537.     if(Buffer = (struct Buffer *)AllocVecPooled(sizeof(struct Buffer),MEMF_ANY | MEMF_CLEAR))
  538.     {
  539.         BPTR SomeLock;
  540.  
  541.             /* Provide basic information. */
  542.  
  543.         DateStamp(&Buffer -> OpenDate);
  544.  
  545.         Buffer -> WriteAccess = TRUE;
  546.  
  547.         Buffer -> SimpleIO = TRUE;
  548.  
  549.             /* Open the file. */
  550.  
  551.         switch(AccessMode[0])
  552.         {
  553.             case 'r':
  554.  
  555.                 if(AccessMode[1] == '+')
  556.                     Buffer -> FileHandle = Open(Name,MODE_READWRITE);
  557.                 else
  558.                 {
  559.                     Buffer -> WriteAccess = FALSE;
  560.  
  561.                     Buffer -> FileHandle = Open(Name,MODE_OLDFILE);
  562.                 }
  563.  
  564.                 break;
  565.  
  566.             case 'w':
  567.  
  568.                 if(AccessMode[1] == '+')
  569.                 {
  570.                     if(SomeLock = Lock(Name,ACCESS_WRITE))
  571.                     {
  572.                         UnLock(SomeLock);
  573.  
  574.                         DeleteFile(Name);
  575.                     }
  576.  
  577.                     Buffer -> FileHandle = Open(Name,MODE_READWRITE);
  578.                 }
  579.                 else
  580.                     Buffer -> FileHandle = Open(Name,MODE_NEWFILE);
  581.  
  582.                 break;
  583.  
  584.             case 'a':
  585.  
  586.                 if(SomeLock = Lock(Name,ACCESS_WRITE))
  587.                 {
  588.                     UnLock(SomeLock);
  589.  
  590.                     if(Buffer -> FileHandle = Open(Name,MODE_READWRITE))
  591.                     {
  592.                         if(Seek(Buffer -> FileHandle,0,OFFSET_END) == -1)
  593.                         {
  594.                             Close(Buffer -> FileHandle);
  595.  
  596.                             Buffer -> FileHandle = NULL;
  597.                         }
  598.                     }
  599.                 }
  600.                 else
  601.                     Buffer -> FileHandle = Open(Name,MODE_NEWFILE);
  602.  
  603.                 break;
  604.         }
  605.  
  606.             /* Did we succeed in opening the file? */
  607.  
  608.         if(Buffer -> FileHandle)
  609.         {
  610.                 /* To keep track of the free space still
  611.                  * available on the filing system.
  612.                  */
  613.  
  614.             if(Buffer -> WriteAccess)
  615.             {
  616.                 Buffer -> InfoPort = ((struct FileHandle *)BADDR(Buffer -> FileHandle)) -> fh_Type;
  617.  
  618.                 ObtainInfo(Buffer);
  619.             }
  620.  
  621.                 /* Link the file into the list. */
  622.  
  623.             ObtainSemaphore(&DoubleBufferSemaphore);
  624.  
  625.             AddTail(&DoubleBufferList,(struct Node *)Buffer);
  626.  
  627.             ReleaseSemaphore(&DoubleBufferSemaphore);
  628.  
  629.             return(Buffer);
  630.         }
  631.         else
  632.             FreeVecPooled(Buffer);
  633.     }
  634.  
  635.     return(NULL);
  636. }
  637.  
  638.     /* OpenFileBuffered(STRPTR Name,STRPTR AccessMode):
  639.      *
  640.      *    Open double-buffered file.
  641.      */
  642.  
  643. STATIC struct Buffer * __regargs
  644. OpenFileBuffered(STRPTR Name,STRPTR AccessMode)
  645. {
  646.     struct Buffer    *Buffer;
  647.     LONG         Size;
  648.  
  649.     Size = (Config -> MiscConfig -> IOBufferSize + 15) & ~15;
  650.  
  651.     if(Size < 2048)
  652.         Size = 2048;
  653.  
  654.         /* Allocate the buffer data. */
  655.  
  656.     do
  657.     {
  658.         Buffer = (struct Buffer *)AllocVecPooled(sizeof(struct Buffer) + ((Size + 15) & ~15) * BUFFER_NUMBER + 15,MEMF_ANY | MEMF_CLEAR);
  659.  
  660.         Size /= 2;
  661.     }
  662.     while(!Buffer && Size > 2048);
  663.  
  664.     if(Buffer)
  665.     {
  666.         struct Process    *Process;
  667.         WORD         i;
  668.  
  669.             /* Set up the first buffer. */
  670.  
  671.         Buffer -> DataBuffer[0] = (UBYTE *)(((ULONG)(Buffer + 1) + 15) & ~15);
  672.  
  673.             /* Set up the individual buffers. */
  674.  
  675.         for(i = 1 ; i < BUFFER_NUMBER ; i++)
  676.             Buffer -> DataBuffer[i] = Buffer -> DataBuffer[i - 1] + Size;
  677.  
  678.         Buffer -> BufLength    = Size;
  679.         Buffer -> WriteBufFull    = Buffer -> BufLength;
  680.  
  681.             /* Create the asynchronous file server. */
  682.  
  683.         if(!(Process = CreateNewProcTags(
  684.             NP_Entry,    FileBufferServer,
  685.             NP_Name,    "term File Process",
  686.             NP_Priority,    SysBase -> ThisTask -> tc_Node . ln_Pri,
  687.             NP_StackSize,    8192,
  688.             NP_WindowPtr,    -1,
  689.         TAG_DONE)))
  690.         {
  691.             FreeVecPooled(Buffer);
  692.  
  693.             return(NULL);
  694.         }
  695.  
  696.             /* Set up the message header. */
  697.  
  698.         Buffer -> Message . mn_Length    = sizeof(struct Buffer);
  699.  
  700.         Buffer -> ActionData[ARG_NAME]    = (LONG)Name;
  701.         Buffer -> ActionData[ARG_MODE]    = (LONG)AccessMode;
  702.  
  703.         Buffer -> Child            = Process;
  704.         Buffer -> Caller        = (struct Process *)SysBase -> ThisTask;
  705.  
  706.         Forbid();
  707.  
  708.             /* Send it to the waiting server process. */
  709.  
  710.         PutMsg(&Process -> pr_MsgPort,&Buffer -> Message);
  711.  
  712.             /* Wait for ringback. */
  713.  
  714.         ClrSignal(SIG_HANDSHAKE);
  715.  
  716.         Wait(SIG_HANDSHAKE);
  717.  
  718.         Permit();
  719.  
  720.             /* Do we have a valid filehandle? */
  721.  
  722.         if(!Buffer -> FileHandle)
  723.         {
  724.             FreeVecPooled(Buffer);
  725.  
  726.             return(NULL);
  727.         }
  728.         else
  729.             return(Buffer);
  730.     }
  731.  
  732.     return(NULL);
  733. }
  734.  
  735.     /* BPrintf():
  736.      *
  737.      *    Prints text into a buffered file.
  738.      */
  739.  
  740. LONG __stdargs
  741. BPrintf(struct Buffer *Buffer,STRPTR Format,...)
  742. {
  743.     UBYTE    String[256];
  744.     va_list    VarArgs;
  745.  
  746.     va_start(VarArgs,Format);
  747.     VSPrintf(String,Format,VarArgs);
  748.     va_end(VarArgs);
  749.  
  750.     return(BufferWrite(Buffer,String,strlen(String)));
  751. }
  752.  
  753.     /* BufferFlush(struct Buffer *Buffer):
  754.      *
  755.      *    Flush the contents of a given buffer to disk.
  756.      */
  757.  
  758. BYTE __regargs
  759. BufferFlush(struct Buffer *Buffer)
  760. {
  761.     if(Buffer -> LastActionFailed)
  762.         return(FALSE);
  763.     else
  764.     {
  765.         if(Buffer -> BufPosition && Buffer -> Written)
  766.         {
  767.             Buffer -> Action = BUF_FLUSH;
  768.  
  769.             Forbid();
  770.  
  771.             Signal(Buffer -> Child,SIG_COMMAND);
  772.  
  773.             ClrSignal(SIG_HANDSHAKE);
  774.  
  775.             Wait(SIG_HANDSHAKE);
  776.  
  777.             Permit();
  778.         }
  779.  
  780.         return(TRUE);
  781.     }
  782. }
  783.  
  784.     /* BufferClose(struct Buffer *Buffer):
  785.      *
  786.      *    Close a buffered filehandle.
  787.      */
  788.  
  789. BYTE __regargs
  790. BufferClose(struct Buffer *Buffer)
  791. {
  792.     if(IsValidBuffer(Buffer))
  793.     {
  794.         BYTE Success;
  795.  
  796.             /* Unbuffered file handle? */
  797.  
  798.         if(Buffer -> SimpleIO)
  799.         {
  800.                 /* Close the file. */
  801.  
  802.             if(Close(Buffer -> FileHandle))
  803.                 Success = TRUE;
  804.             else
  805.                 Success = FALSE;
  806.  
  807.                 /* Unlink the handle. */
  808.  
  809.             ObtainSemaphore(&DoubleBufferSemaphore);
  810.  
  811.             Remove((struct Node *)Buffer);
  812.  
  813.             ReleaseSemaphore(&DoubleBufferSemaphore);
  814.         }
  815.         else
  816.         {
  817.             Buffer -> Action = BUF_CLOSE;
  818.  
  819.             Forbid();
  820.  
  821.             Signal(Buffer -> Child,SIG_COMMAND);
  822.  
  823.             ClrSignal(SIG_HANDSHAKE);
  824.  
  825.             Wait(SIG_HANDSHAKE);
  826.  
  827.             Permit();
  828.  
  829.             Success = Buffer -> Result;
  830.         }
  831.  
  832.         FreeVecPooled(Buffer);
  833.  
  834.         return(Success);
  835.     }
  836.     else
  837.         return(FALSE);
  838. }
  839.  
  840.     /* BufferOpen(STRPTR Name,STRPTR AccessMode):
  841.      *
  842.      *    Open a file for buffered I/O.
  843.      */
  844.  
  845. struct Buffer * __regargs
  846. BufferOpen(STRPTR Name,STRPTR AccessMode)
  847. {
  848.         /* Simple file handling? */
  849.  
  850.     if(Config -> MiscConfig -> SimpleIO)
  851.         return(OpenFileSimple(Name,AccessMode));
  852.     else
  853.     {
  854.         struct Buffer *Buffer;
  855.  
  856.             /* Try to open a buffered file, if unsuccessful
  857.              * fall back to simple file I/O.
  858.              */
  859.  
  860.         if(!(Buffer = OpenFileBuffered(Name,AccessMode)))
  861.             Buffer = OpenFileSimple(Name,AccessMode);
  862.  
  863.         return(Buffer);
  864.     }
  865. }
  866.  
  867.     /* BufferSeek(struct Buffer *Buffer,LONG Offset,LONG Origin):
  868.      *
  869.      *    Move the read/write pointer to a specific position
  870.      *    in a file (not really buffered).
  871.      */
  872.  
  873. BYTE __regargs
  874. BufferSeek(struct Buffer *Buffer,LONG Offset,LONG Origin)
  875. {
  876.     if(Buffer -> SimpleIO)
  877.     {
  878.         if(Seek(Buffer -> FileHandle,Offset,Origin) == -1)
  879.             return(FALSE);
  880.         else
  881.             return(TRUE);
  882.     }
  883.     else
  884.     {
  885.         Buffer -> Action            = BUF_SEEK;
  886.         Buffer -> ActionData[ARG_OFFSET]    = Offset;
  887.         Buffer -> ActionData[ARG_ORIGIN]    = Origin;
  888.  
  889.         Forbid();
  890.  
  891.         Signal(Buffer -> Child,SIG_COMMAND);
  892.  
  893.         ClrSignal(SIG_HANDSHAKE);
  894.  
  895.         Wait(SIG_HANDSHAKE);
  896.  
  897.         Permit();
  898.  
  899.         if(Buffer -> Result == -1)
  900.             return(FALSE);
  901.         else
  902.             return(TRUE);
  903.     }
  904. }
  905.  
  906.     /* BufferRead():
  907.      *
  908.      *    Read data from a file (buffered).
  909.      */
  910.  
  911. LONG __regargs
  912. BufferRead(struct Buffer *Buffer,STRPTR Destination,LONG Size)
  913. {
  914.     if(Buffer -> SimpleIO)
  915.     {
  916.         LONG Bytes;
  917.  
  918.         Buffer -> Used = TRUE;
  919.  
  920.         if((Bytes = Read(Buffer -> FileHandle,Destination,Size)) < 0)
  921.             Bytes = 0;
  922.  
  923.         return(Bytes);
  924.     }
  925.     else
  926.     {
  927.         LONG     BytesRead = 0,ToCopy,BufPosition,ReadBufFull;
  928.         UBYTE    *Data;
  929.  
  930.             /* If there is still data to be written in
  931.              * the buffer, write it.
  932.              */
  933.  
  934.         if(Buffer -> Written)
  935.         {
  936.             if(!BufferFlush(Buffer))
  937.                 return(0);
  938.         }
  939.  
  940.             /* Set up for read access. */
  941.  
  942.         BufPosition    = Buffer -> BufPosition;
  943.         ReadBufFull    = Buffer -> ReadBufFull;
  944.         Data        = &Buffer -> Data[BufPosition];
  945.  
  946.             /* Remember access. */
  947.  
  948.         Buffer -> Used    = TRUE;
  949.  
  950.             /* Continue until all data has been processed. */
  951.  
  952.         while(Size)
  953.         {
  954.                 /* Determine number of bytes to transfer. */
  955.  
  956.             if(ToCopy = (Size > ReadBufFull) ? ReadBufFull : Size)
  957.             {
  958.                 CopyMem(Data,Destination,ToCopy);
  959.  
  960.                 Size        -= ToCopy;
  961.                 BufPosition    += ToCopy;
  962.                 ReadBufFull    -= ToCopy;
  963.                 Destination    += ToCopy;
  964.                 Data        += ToCopy;
  965.                 BytesRead    += ToCopy;
  966.             }
  967.             else
  968.             {
  969.                     /* Refill buffer with data. */
  970.  
  971.                 Buffer -> BufPosition    = BufPosition;
  972.                 Buffer -> ReadBufFull    = ReadBufFull;
  973.  
  974.                 if(!BufferFill(Buffer))
  975.                     return(BytesRead);
  976.  
  977.                 if(!Buffer -> ReadBufFull)
  978.                 {
  979.                     Buffer -> BufPosition = BufPosition;
  980.  
  981.                     return(BytesRead);
  982.                 }
  983.  
  984.                     /* Pick up new data. */
  985.  
  986.                 BufPosition        = Buffer -> BufPosition;
  987.                 ReadBufFull        = Buffer -> ReadBufFull;
  988.                 Data            = Buffer -> Data;
  989.             }
  990.         }
  991.  
  992.             /* Install new data. */
  993.  
  994.         Buffer -> BufPosition    = BufPosition;
  995.         Buffer -> ReadBufFull    = ReadBufFull;
  996.  
  997.         return(BytesRead);
  998.     }
  999. }
  1000.  
  1001.     /* BufferWrite():
  1002.      *
  1003.      *    Write data to a file (buffered).
  1004.      */
  1005.  
  1006. LONG __regargs
  1007. BufferWrite(struct Buffer *Buffer,STRPTR Source,LONG Size)
  1008. {
  1009.     if(Buffer -> SimpleIO)
  1010.     {
  1011.         LONG Bytes;
  1012.  
  1013.         Buffer -> Used = TRUE;
  1014.  
  1015.         Buffer -> WriteAccess = TRUE;
  1016.  
  1017.         if((Bytes = Write(Buffer -> FileHandle,Source,Size)) < 0)
  1018.             Bytes = 0;
  1019.         else
  1020.         {
  1021.             Buffer -> BufPosition += Bytes;
  1022.  
  1023.             if(Buffer -> BufPosition >= Config -> MiscConfig -> IOBufferSize)
  1024.             {
  1025.                 Buffer -> BufPosition = 0;
  1026.  
  1027.                 ObtainInfo(Buffer);
  1028.             }
  1029.         }
  1030.  
  1031.         return(Bytes);
  1032.     }
  1033.     else
  1034.     {
  1035.         LONG     BytesWritten = 0,ToCopy,BufPosition,WriteBufFull;
  1036.         UBYTE    *Data;
  1037.  
  1038.             /* If there is still read data in the buffer,
  1039.              * reset the control information.
  1040.              */
  1041.  
  1042.         if(Buffer -> Read)
  1043.         {
  1044.             Buffer -> WriteBufFull    = Buffer -> BufLength;
  1045.             Buffer -> BufPosition    = 0;
  1046.             Buffer -> Read        = FALSE;
  1047.         }
  1048.  
  1049.             /* Set up for write access. */
  1050.  
  1051.         Buffer -> Written = TRUE;
  1052.  
  1053.         BufPosition    = Buffer -> BufPosition;
  1054.         WriteBufFull    = Buffer -> WriteBufFull;
  1055.         Data        = &Buffer -> Data[BufPosition];
  1056.  
  1057.             /* Remember access. */
  1058.  
  1059.         Buffer -> Used    = TRUE;
  1060.  
  1061.             /* Continue until all data has been processed. */
  1062.  
  1063.         while(Size)
  1064.         {
  1065.                 /* Determine number of bytes to transfer. */
  1066.  
  1067.             if(ToCopy = (Size > WriteBufFull ? WriteBufFull : Size))
  1068.             {
  1069.                 CopyMem(Source,Data,ToCopy);
  1070.  
  1071.                 Size        -= ToCopy;
  1072.                 BufPosition    += ToCopy;
  1073.                 WriteBufFull    -= ToCopy;
  1074.                 Source        += ToCopy;
  1075.                 Data        += ToCopy;
  1076.                 BytesWritten    += ToCopy;
  1077.             }
  1078.             else
  1079.             {
  1080.                     /* Flush the contents of the
  1081.                      * write buffer.
  1082.                      */
  1083.  
  1084.                 Buffer -> BufPosition    = BufPosition;
  1085.                 Buffer -> WriteBufFull    = WriteBufFull;
  1086.  
  1087.                 if(!BufferFlush(Buffer))
  1088.                     return(BytesWritten);
  1089.  
  1090.                     /* Pick up new data. */
  1091.  
  1092.                 BufPosition        = Buffer -> BufPosition;
  1093.                 WriteBufFull        = Buffer -> WriteBufFull;
  1094.                 Data            = Buffer -> Data;
  1095.  
  1096.                     /* Important - or BufferFlush() won't
  1097.                      * write the final buffer contents when
  1098.                      * the buffered file handle is freed up.
  1099.                      */
  1100.  
  1101.                 Buffer -> Written = TRUE;
  1102.             }
  1103.         }
  1104.  
  1105.             /* Install new data. */
  1106.  
  1107.         Buffer -> BufPosition    = BufPosition;
  1108.         Buffer -> WriteBufFull    = WriteBufFull;
  1109.  
  1110.         return(BytesWritten);
  1111.     }
  1112. }
  1113.